/**
 * @file grafo.h
 * Contém as estruturas da matriz e do grafo e as funções para gerar os dois.
 */

#ifndef GRAFO_H_
#define GRAFO_H_

#include <stdbool.h>
#include <limits.h>


/**
 * Quantidade máxima de vizinhos que um comutador pode ter.
 */
#define MAXVIZINHOS 20


/**
 * Valor bem alto, para representar infinito.
 */
#define INF 2000000000


/**
 * Representa um nó da matriz.
 */
typedef struct {
	int x;			///< Coordenada x do nó, que é equivalente ao número da coluna do mesmo
	int y;			///< Coordenada y do nó, que é equivalente ao número da linha do mesmo
} no_t;


/**
 * Matriz onde serão plotados os nós do grafo.
 * Os índices da matriz representam as coordenadas (y,x) da célula, ou seja, a
 * linha representa a coordenada y e a coluna a coordenada x.
 */
typedef struct {
	int altura;			///< Quantidade de linhas da matriz
	int largura;		///< Quantidade de colunas da matriz
	int quant_nos;		///< Quantidade de nós na matriz
	no_t *no;			///< Array com as coordenadas dos nós
	int **celula;		///< As células contendo o número do nó ou -1 caso esteje vazia
} matriz_t;


/**
 * O grafo que representa as conexões entre os comutadores, i.e., a topologia da
 * rede.
 * Para cada vértice do grafo é possível saber a quantidade de vizinhos, quem
 * são os vizinhos, o peso da aresta para cada vizinho, o custo para chegar em
 * qualquer outro vértice, o melhor caminho para qualquer vértice e se esse
 * comutador atualizou sua tabela da última vez.
 * Como peso da aresta usa-se a distância quadrada entre os vértices.
 */
typedef struct {
	int **custo;			///< custo[i][j] indica o custo para ir de 'i' a 'j', segundo o próprio 'i'
	int **caminho;			///< caminho[i][j] indica pra qual vértice 'i' tem que mandar pra chegar em 'j'
	bool *atualizou;		///< atualizou[i] informa se o vértice 'i' foi atualizado na última rodada
	int **vizinho;			///< vizinho[i] é um array com todos os vizinhos do vértice 'i'
	int *quant_vizinhos;	///< quant_vizinhos[i] é a quantidade de vértices conectados diretamente ao vértice 'i'
	int quant_vertices;		///< quant_vertices é a quantidade de vértices total do grafo
} grafo_t;


/**
 * Cria uma matriz e aloca os nós nas posições corretas, ou seja, dentro de um
 * quadrado de distância menor ou igual a 'raio', em relação ao nó anterior.
 * Os nós nunca são alocados nas bordas da matriz, isto é, sempre estarão a uma
 * distância maior ou igual a 'raio' das bordas.
 *
 * @param altura Quantidade de linhas
 * @param largura Quantidade de colunas
 * @param nos Quantidade de nós
 * @param raio Maior distância aproximada entre um ponto e o seguinte
 * @return A matriz já totalmente preenchida
 */
matriz_t new_matriz(int altura, int largura, int nos, int raio);


/**
 * Apaga uma matriz criada com a função new_matriz.
 *
 * @param matriz A matriz a ser apagada
 */
void del_matriz(matriz_t matriz);


/**
 * Cria um grafo a partir de uma matriz. A matriz deve estar preenchida com os
 * pontos que representam os roteadores. O grafo gerado irá conectar os
 * roteadores que estiverem a uma distância de até 'raio', irá montar as listas
 * de adjacências e calcular o custo das arestas.
 *
 * @param matriz A matriz que será usada para gerar o grafo
 * @param raio A distância máxima que dois roteadores podem estar para serem conectados
 * @return O grafo gerado, já com tudo preenchido
 */
grafo_t new_grafo(matriz_t matriz, int raio);


/**
 * Apaga um grafo, liberando qualquer memória alocada e zerando as variáveis.
 *
 * @param grafo O grafo a ser apagado
 */
void del_grafo(grafo_t grafo);


/**
 * Faz um comutador enviar sua tabela para todos os seus vizinhos.
 *
 * @param grafo O grafo com a topologia da rede
 * @param comutador O número do comutador que vai enviar sua tabela
 */
void envia_vizinhos(grafo_t grafo, int comutador);


/**
 * Faz um comutador processar o seu buffer, lendo as tabelas que estão nele e
 * atualizando os valores da sua tabela.
 * Se ele atualizar algum valor de sua tabela, a variável 'atualizou' desse
 * vértice recebe true.
 *
 * @param grafo O grafo com a topologia da rede
 * @param O número do comutador que irá realizar o processamento
 */
void processa_buffer(grafo_t grafo, int comutador);


#endif /* GRAFO_H_ */
